#ifndef file_file_h
#define file_file_h

#include <common/include/interface.h>
#include <common/include/memory.h>

namespace io{
	using cmn::mem;
	using cmn::byte;
	using cmn::dword;
	using cmn::kbyte;
	using cmn::kcstr;
	using cmn::kcwstr;

	class file : public cmn::interface_t, public cmn::noncopyable
	{
	public:
		enum seek_dir { head = 0, tail, current };

		virtual bool	open(kcwstr _file_name)	= 0;

		virtual bool	open(kcstr _file_name)	= 0;

		virtual void	close()					= 0;

		virtual bool	seek(dword _offset, seek_dir _dir = current) = 0;

		virtual bool	is_open()	const = 0;

		virtual dword	tell()		const = 0;

		virtual dword	length()	const = 0;

		virtual kcstr	name()		const = 0;
	};

	class ifile : public file
	{
	public:
		virtual dword	read(void* _mem, dword _size)	= 0;

		virtual dword	length_readed() const			= 0;
	};

	class ofile : public file
	{
	public:
		virtual dword	write(const void* _mem, dword _size) = 0;
	};

	ifile*	create_ifile();

	ofile*	create_ofile();

	ifile*	read_file(kcstr _file_name);

	ifile*	read_file(kcwstr _file_name); 
	
	ofile*	write_file(kcstr _file_name);

	ofile*	write_file(kcwstr _file_name);

	mem		def_read_whole_file(kcstr _file_name);

	mem		def_read_whole_file(kcwstr _file_name);

	template<class raw_type>
	inline dword read(ifile* _ifile, const raw_type& _value)
	{
		return _ifile->read(&value, sizeof(raw_type));
	}

	template<>
	inline dword read(ifile* _ifile, const mem& _value)
	{
		return _ifile->read((void*)_value, _value.length());
	}

	template<class raw_type>
	inline dword write(ofile* _ofile, const raw_type& _value)
	{
		return _ofile->write(&_value, sizeof(raw_type));
	}

	template<>
	inline dword write(ofile* _ofile, const mem& _value)
	{
		return _ofile->write((void*)_value, _value.length());
	}

	inline dword write(ofile* _ofile, kcstr _value)
	{
		kcstr str = _value;
		while (*str++ != '\0');
		return _ofile->write(_value, sizeof(char) *(str - _value - 1));
	}

	inline dword write(ofile* _ofile, kcwstr _value)
	{
		kcwstr str = _value;
		while (*str++ != L'\0');
		return _ofile->write(_value, sizeof(wchar_t) * (str - _value - 1));
	}
}

#endif
